/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

#ifndef B2_FIXTURE_H
#define B2_FIXTURE_H

#include "b2Body.h"
#include "../Collision/b2Collision.h"
#include "../Collision/Shapes/b2Shape.h"

class b2BlockAllocator;
class b2Body;
class b2BroadPhase;

/// This holds contact filtering data.
struct b2FilterData
{
	// The Collision category bits.Normally you wold just set one bit.
	uint16 categoryBits;

	// The collision mask bits.This states the categories that this shapes would 
	// accept for collision.
	uint16 maskBits;

	// Collision groups allow a certain group of object to never collide(negative)
	// or alwase collide(positive).Zero means no collision  groups. Non-zero groups
	// filtering always win aginst the mask bits.
	uint16 groupIndex;
};

// A FixtureDef is used to create a fixture.this class define a abstract fixture definition
// you can reuser fixture definiation safely.
struct b2FixtureDef 
{
	/// The constructor sets the default fixture definition values.
	b2FixtureDef()
	{
		
	}

	/// Holds the shape type for down-casting.
	b2ShapeType type;

	/// Use this to store application specific fixture data.
	void* userData;

	/// the friction coefficient,usually in the range of [0, 1];
	float32 friction;

	/// the restitution (elasticity) usually in the range of [0, 1].
	float32 restitution;

	/// The density usually in kg/m^2
	float32 density;

	/// A sensor shape collects contact information but never generates a collision response.
	bool isSensor;

	/// Contact filtering data.
	b2FilterData filter;
};

/// This structure is used to build a fixture with a circle shape.
struct b2CircleDef : public b2FixtureDef
{
	b2CircleDef()
	{
		type = b2_circleShape;
		localPosition.SetZero();
		radius = 1.0f;
	}

	b2Vec2 localPosition;
	float32 radius;
};

/// This struct is used to build a chain of shape.
struct b2EdgeDef : public b2FixtureDef
{
	b2EdgeDef()
	{
		type = b2_edgeShape;
	}

	/// The start vertex.
	b2Vec2 vertex1;

	/// The end vertex.
	b2Vec2 vertex2;
};

/// Convex polygon. the vertices must be ordered so that the outside of the polygon is on the right side of 
/// the edges(looking along the edge from the start to the end)
struct b2PolygonDef : public b2FixtureDef
{
	b2PolygonDef()
	{
		type = b2_polygonShape;
		vertexCount = 0;
	}

	/// Build vertices to represent an axis-aligned box.
	/// @param  hx the half-widh.
	/// @param  hy the half-height.
	void SetAsBox(float32 hx, float32 hy);

	/// Build vertices to represent an oriented box.
	/// @param hx the half-width.
	/// @param hy the half-height.
	/// @param center the center of the box in local coordinates.
	/// @param angle the rotation of the box in local coordinates.
	void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle);

	/// The polygon vertices in local coordinates.
	b2Vec2 vertices[b2_maxPolygonVertices];

	/// The number of polygon vertices.
	int32 vertexCount;
};

/// A fixture is used to attach a shape to a body for collision detection. A fixture
/// inherits its transform from its parent.Fixture hold additional non-geomitric data.
/// such as friction, collision filters, etc.
/// Fixtures are created via b2Body::CreateFixture.
/// Warning you can not reuse Fixture.
class b2Fixture
{
public:
	// Get the type of the child shape.You can use this to down case to a concreate shape.
	// return the shape type.
	b2ShapeType GetType()const { return m_type; }

	// Get the child shape.You can change the child shape, however you should not change the 
	// number of vertices because this will crash some collision caching mechanisms.
	const b2Shape* GetShape() const { return m_shape; }
	b2Shape* GetShape() { return m_shape; }

	// Is this fixture a sensor.
	// return true if the shape is a sensor.
	bool IsSensor() const { return m_isSensor; }

	// Set if the shape is sensor. You must call b2World::Refilter to update contacts.
	void SetSensor(bool sensor)	{ m_isSensor = sensor; }

	// Set the contact filter data. You must call b2World::Refilter to update existing constacts/non-contacts.
	void SetFilterData(const b2FilterData& filter)	{ m_filter = filter; }

	// Get the contactiong filter data.
	const b2FilterData& GetFilterData() const	{ return m_filter; }

	// Get the parent body of this fixture.This is NULL if the fixture is not attached.
	// @return the fixture body.
	b2Body* GetBody()	{ return m_body; }

	// Get the next fixture is the parent body's fixture list.
	// @return the next shape.
	b2Fixture* GetNext() { return m_next; }

	// Get the user data that was assigned in the fixture difinition. Use this to store your
	// application specific data.
	void* GetUserData() { return m_userData; }
	
	// Set User data.
	void SetUserData(void* data)	{ m_userData = data; }

	// Test a point for containment in this fixture.This only works for convex shape.
	// @param xf the shape's world transform.
	// param p a point in the world coordinates.
	bool TestPoint(const b2Vec2& p) const { m_shape->TestPoint(m_body->GetXForm(), p); }

	// Perform a ray cast against this shape.
	// @param xf the shape world transform.
	// @param lambda return the hit friction.You can use this to compute contacct point.
	// p = (1-lambda) * segment.p1 + lambda * segment.p2
	// @param normal return the normal at the contact point.If there is no intersection the normal is not set.
	// @param segment define the start and end of the ray cast.
	// @param maxLambda a number typically in range [0, 1]
	b2SegmentCollide TestSegment(float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const { return m_shape->TestSegment(m_body->GetXForm(), lambda, normal, segment, maxLambda); }

	// Compute the mass properties of this shape.using its dimensions and density.
	// This inertia tensor is computed about the local origin.not the centriod.
	// @param massData return the mass data for this shape.
	void ComputeMass(b2MassData* massData) const { m_shape->ComputeMass(massData, m_desity); }

	// Compute the volume and centriod of this fixture intersected with a half plane.
	// @param normal the surface normal.
	// @param offset the surface offset along normal.
	// @param c return the centriod.
	// @param return the total volume less than offset along the normal.
	float32 ComputeSubmergedArea(const b2Vec2& normal, float32 offset, b2Vec2* c) const { return m_shape->ComputeSubmergedArea(normal, offset, m_body->GetXForm(), c); }

	// Get the maxmum radius about the parent body's center of mass.
	float32 ComputeSweepRadius(const b2Vec2& pivot) const { return m_shape->ComputeSweepRadius(pivot); }

	// Get the coefficient of friction.
	float32 GetFriction() const { return m_friction; }

	// Set the coefficient of friction.
	void SetFriction(float32 friction) { m_friction = friction; }

	// Get the coefficient of restitution.
	float32 GetRestitution() const { return m_restitution; }

	// Set the coefficient of the restitution.
	void SetRestitution(float32 restitution) { m_restitution = restitution; }

	// Get the density.
	float32 GetDensity() const { return m_desity; }

	// Set the density.
	// @warning this dosed not automatic update the mass of the parent body.
	void SetDensity(float32 density) { m_desity = density; }

protected:
	friend class b2Body;
	friend class b2World;

	b2Fixture();
	~b2Fixture();

	// We need separate create/destroy functions from the constructor/destructor because the 
	// destructor can not access the allocator or broadephase(no destructor argument allowed by C++)
	void Create(b2BlockAllocator* allocator, b2BroadPhase* broadPhase, b2Body* body, const b2XForm& xf, const b2FixtureDef* def);
	void Destroy(b2BlockAllocator* allocator, b2BroadPhase* broadPhase);

	bool Synchronize(b2BroadPhase* broadPahse, const b2XForm& xf1, const b2XForm& xf2);
	void RefilterProxy(b2BroadPhase* broadPhase, const b2XForm& xf);

	b2ShapeType m_type;
	b2Fixture* m_next;
	b2Body* m_body;

	b2Shape* m_shape;

	float32 m_desity;
	float32 m_friction;
	float32 m_restitution;

	uint16 m_proxyId;
	b2FilterData m_filter;

	bool m_isSensor;
	void* m_userData;
};

#endif